package com.yaodian100.ec.member.service.impl;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Serializable;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.providers.encoding.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;

import com.yaodian100.core.admin.service.impl.JCEPasswordEncoder;
import com.yaodian100.core.common.dao.ObjectDao;
import com.yaodian100.core.common.dao.impl.CommonCriteria;
import com.yaodian100.core.common.entity.SimplePager;
import com.yaodian100.core.common.exception.CoreException;
import com.yaodian100.core.common.service.impl.DomainServiceImpl;
import com.yaodian100.core.common.utils.DateUtil;
import com.yaodian100.core.common.utils.PasswordUtils;
import com.yaodian100.core.common.utils.ServerValue;
import com.yaodian100.core.mail.entity.Mail;
import com.yaodian100.core.mail.service.MailService;
import com.yaodian100.core.menu.entity.Option;
import com.yaodian100.core.menu.service.MenuService;
import com.yaodian100.core.sms.service.SmsService;
import com.yaodian100.core.template.service.TemplateService;
import com.yaodian100.ec.campaign.entity.Campaign;
import com.yaodian100.ec.campaign.service.CampaignService;
import com.yaodian100.ec.common.EcConstant;
import com.yaodian100.ec.generate.service.GenerateOrderService;
import com.yaodian100.ec.member.entity.AddressBook;
import com.yaodian100.ec.member.entity.Balance;
import com.yaodian100.ec.member.entity.BlackBook;
import com.yaodian100.ec.member.entity.BlackBookImportResult;
import com.yaodian100.ec.member.entity.BlackList;
import com.yaodian100.ec.member.entity.Bonus;
import com.yaodian100.ec.member.entity.GreyBook;
import com.yaodian100.ec.member.entity.ImageValid;
import com.yaodian100.ec.member.entity.LoginHistory;
import com.yaodian100.ec.member.entity.Member;
import com.yaodian100.ec.member.entity.MemberMemo;
import com.yaodian100.ec.member.entity.MemberProfile;
import com.yaodian100.ec.member.entity.ReceiverBlackBook;
import com.yaodian100.ec.member.entity.ViewWishList;
import com.yaodian100.ec.member.entity.VirtualBalance;
import com.yaodian100.ec.member.entity.WishList;
import com.yaodian100.ec.member.entity.VirtualBalance.VirtualBalancePayType;
import com.yaodian100.ec.member.service.MemberService;
import com.yaodian100.ec.memberevent.entity.MemberEvent;
import com.yaodian100.ec.memberevent.entity.MemberGift;
import com.yaodian100.ec.memberevent.service.MemberEventService;

public class MemberServiceImpl extends DomainServiceImpl<Member> implements MemberService {
	private static final String BLOCK_REASON_FOR_GREY_TO_BLACK_BOOK = "1";

	private static final String BLACK_BOOK_BLOCK_STATUS_NO = "N";

	private static final String FIELD_NAME_BLACK_BOOK_ID = "id";

	public static final String BLACK_BOOK_BLOCK_STATUS_YES = "Y";

	private static final String FIELD_NAME_MEMBER_ID = "memberId";

	@Autowired
	private JdbcTemplate jdbcTemplate;

	/** passwordEncoder, default: PlaintextPasswordEncoder() */
	private ObjectDao<LoginHistory> loginHistoryDao;
	private ObjectDao<Balance> balanceDao;
	private ObjectDao<Bonus> bonusDao;
	private ObjectDao<VirtualBalance> virtualBalanceDao;
	private ObjectDao<WishList> wishListDao;
	private ObjectDao<AddressBook> addressBookDao;
	private ObjectDao<BlackList> blackListDao;
	private ObjectDao<ImageValid> imageValidDao;
	private ObjectDao<ViewWishList> viewWishListDao;
	private ObjectDao<MemberMemo> memberMemoDao;
	private ObjectDao<MemberProfile> memberProfileDao;
	private ObjectDao<ReceiverBlackBook> receiverBlackBookDao;
	private ObjectDao<GreyBook> greyBookDao;
	private ObjectDao<BlackBook> blackBookDao;

	private PasswordEncoder passwordEncoder = new JCEPasswordEncoder();
	private TemplateService velocityService;

	private MailService mailService;
	private SmsService smsService;
	private MemberEventService memberEventService;

	@Resource
	private GenerateOrderService generateOrderService;

	@Resource
	private CampaignService campaignService;

	@Autowired
	private MenuService menuService;

	private String mailFrom;

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#checkActivateData(java.lang.String, java.lang.String)
	 */
	@Override
	public Member checkActivateData(String memberId, String activeToken) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		List<Member> members = getList(0, -1, crit, null);
		if (members.size() == 1) {
			Member member = members.get(0);
			if (activeToken.equals(member.getActivateToken())) {
				return member;
			}
		}
		return null;
	}

	@Override
	public boolean checkAddressBookExist(AddressBook addressBook) throws CoreException {
		// 检查是否有重复的地址簿资料
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, addressBook.getMemberId());
		crit.addEq("contactName", addressBook.getContactName());
		crit.addEq("zipCode", addressBook.getZipCode());
		crit.addEq("province", addressBook.getProvince());
		crit.addEq("city", addressBook.getCity());
		crit.addEq("district", addressBook.getDistrict());
		crit.addEq("addr", addressBook.getAddr());
		crit.addEq("areaCode", addressBook.getAreaCode());
		crit.addEq("mobile", addressBook.getMobile());
		crit.addEq("phone", addressBook.getPhone());
		crit.addEq("extension", addressBook.getExtension());
		int count = getAddressBookDao().getListSize(crit).intValue();
		if (count == 0) {
			return false;
		} else {
			return true;
		}
	}

	@Override
	@Transactional(readOnly = false)
	public Member checkLoginData(String loginId) throws CoreException {
		// TODO 1.确认锁定登入的时间
		// TODO 2.确认重复登入几次失败后要上锁
		CommonCriteria crit = null;
		Member member = null;
		try {
			if (StringUtils.isNotBlank(loginId)) {
				// 写入loginhistory
				LoginHistory loginHistory = new LoginHistory();
				loginHistory.setLoginTime(DateUtil.getCurrentTime());
				loginHistory.setLoginId(loginId);
				loginHistory = loginHistoryDao.save(loginHistory);

				// 更改會員最後logintime
				member = getMemberByLoginId(loginId);
				if (null != member) {// 表示有找到会员资料
					member.setLastLoginTime(loginHistory.getLoginTime());
					member = super.update(member);

					// 同一组帐号被try很多次
					// 计算xx时间内重复登入次数，若太频繁则立刻上锁
					int loginCount = this.getLoginHistorySize(loginId, null, null);
					if (loginCount >= 3 && member.getStatus().equals("00")) {
						// 写入黑名单
						BlackList blackList = new BlackList();
						blackList.setMemberId(member.getMemberId());
						blackList.setBlockStatus(BLACK_BOOK_BLOCK_STATUS_YES);
						blackList.setBlockType("10");
						blackList = getBlackListDao().save(blackList);
						logger.info("blackList size:{}", blackList.getId());
						// 更新会员状态
						member.setBlackListId(blackList.getId());
						member.setStatus(blackList.getBlockType());
						member.setUnBlockDate(null);
						member = super.update(member);
					}
				}
			}
		} catch (Exception e) {
			logger.error("checkLoginData{}:", e);
		}
		return member;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.yaodian100.ec.member.service.MemberService#checkMobileForgetPwdCount(com.yaodian100.ec.member.entity.Member)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member checkMobileForgetPwdCount(Member member) throws CoreException {
		if (StringUtils.isNotBlank(member.getMobile())) {
			DateFormat df = new SimpleDateFormat("yyyyMM");
			if ((null != member.getLastMobileForgetPwdDate())
					&& (!df.format(member.getLastMobileForgetPwdDate()).equals(df.format(new Date())))) {
				member.setLastMobileForgetPwdDate(null);
				member.setMobileForgetPwdCount(0);
				member = super.getDao().update(member);
			}
		}
		return member;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#checkMobileModifyCount(com.yaodian100.ec.member.entity.Member)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member checkMobileModifyCount(Member member) throws CoreException {
		// if (StringUtils.isNotBlank(member.getMobile())) {
		DateFormat df = new SimpleDateFormat("yyyyMM");
		if ((null != member.getLastMobileModifyDate())
				&& (!df.format(member.getLastMobileModifyDate()).equals(df.format(new Date())))) {
			member.setMobileModifyCount(0);
			member = super.getDao().update(member);
		}
		// }
		return member;
	}

	@Override
	public boolean checkWishListExist(WishList wishlist) throws CoreException {
		// 检查是否有重复的收藏资料
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, wishlist.getMemberId());
		if (null == wishlist.getCategoryId()) {
			crit.addEq("productId", wishlist.getProductId());
		} else {
			crit.addEq("categoryId", wishlist.getCategoryId());
		}
		if (getWishListDao().getListSize(crit).intValue() == 0) {
			return false;
		} else {
			return true;
		}
	}

	@Override
	public WishList getWishList(WishList wishlist) throws CoreException {
		// 检查是否已经有收藏资料
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, wishlist.getMemberId());
		if (StringUtils.isNotBlank(wishlist.getProductId())) {
			crit.addEq("productId", wishlist.getProductId());
		} else {
			crit.addEq("categoryId", wishlist.getCategoryId());
		}
		if (getWishListDao().getListSize(crit).intValue() == 0) {
			return null;
		} else {
			return getWishListDao().getList(crit, null).get(0);
		}
	}

	@Override
	@Transactional(readOnly = false)
	public boolean deleteAddressBook(Long id) throws CoreException {
		try {
			getAddressBookDao().deleteByPK(id);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	/**
	 * 删除登入历史记录
	 * 
	 * @param loginId
	 * @throws CoreException
	 */
	@Override
	@Transactional(readOnly = false)
	public void deleteLoginHistory(String loginId) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("loginId", loginId);
		List<LoginHistory> loginHistorys = getLoginHistoryDao().getList(crit, null);
		getLoginHistoryDao().deleteBatch(loginHistorys);
	}

	@Override
	@Transactional(readOnly = false)
	public Member deleteMobile(Member member) throws CoreException {
		member.setActivateMobileToken(null);
		member.setMobile(null);
		super.update(member);
		return member;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#deleteWishList(java.lang.String[])
	 */
	@Override
	@Transactional(readOnly = false)
	public boolean deleteWishList(String[] wishListsId) throws CoreException {
		try {
			if (!ArrayUtils.isEmpty(wishListsId)) {
				for (int i = 0; i < wishListsId.length; i++) {
					getWishListDao().deleteByPK(Integer.parseInt(wishListsId[i]));
				}
				return true;
			}
		} catch (Exception e) {
			return false;
		}
		return false;
	}

	private String generateCode(int length) {
		Random random = new Random();
		String sRand = "";
		String msg = "1234567890";
		for (int i = 0; i < length; i++) {
			int rKey = random.nextInt(msg.length());
			String rand = String.valueOf(msg.substring(rKey, rKey + 1));
			sRand += rand;
		}
		return sRand;
	}

	@Override
	public AddressBook getAddressBook(Long id) throws CoreException {
		AddressBook addressBook = getAddressBookDao().get(id);
		return addressBook;
	}

	@Override
	public List<AddressBook> getCanUseAddressBook(String id, String type, String fromProvince, String fromCity,
			String fromDistrict) throws CoreException {
		return getCanUseAddressBook(id, type, fromProvince, fromCity, fromDistrict, null);
	}

	@Override
	public List<AddressBook> getCanUseAddressBook(String id, String type, String fromProvince, String fromCity,
			String fromDistrict, boolean prodVolume) throws CoreException {
		return getCanUseAddressBook(id, type, fromProvince, fromCity, fromDistrict, null, true);
	}

	@Override
	public List<AddressBook> getCanUseAddressBook(String id, String type, String fromProvince, String fromCity,
			String fromDistrict, String paymentType, boolean prodVolume) throws CoreException {
		StringBuilder sb = new StringBuilder("");
		List<String> attrs = new ArrayList<String>();
		sb.append("Select Distinct Emad.id ");
		sb.append("From Ec_Delivery_Rule Evdr, Ec_Member_Address_Book Emad ");
		if (prodVolume) {// 大材积
			sb.append(", EC_OTHER_DELIVERY_RULE Oevdr ");
			sb.append("Where Evdr.To_Province = Oevdr.To_Province ");
			sb.append("And Evdr.To_City = Oevdr.To_City ");
			sb.append("And Evdr.To_District = Oevdr.To_District ");
		} else {
			sb.append("Where 1 = 1 ");
		}
		sb.append("And Evdr.Type = ? ");
		attrs.add(type);
		sb.append("And Evdr.To_Province = Emad.Province ");
		sb.append("And Evdr.To_City = Emad.City ");
		sb.append("And Evdr.To_District = Emad.District ");

		if ("SCM".equals(type)) {
			if (StringUtils.isNotBlank(fromProvince)) {
				sb.append("And Evdr.From_Province = ? ");
				attrs.add(fromProvince);
			}
			if (StringUtils.isNotBlank(fromCity)) {
				sb.append("And Evdr.From_City = ? ");
				attrs.add(fromCity);
			}
			if (StringUtils.isNotBlank(fromDistrict)) {
				sb.append("And Evdr.From_District = ?");
				attrs.add(fromDistrict);
			}
		} else {
			if (StringUtils.isNotBlank(fromProvince)) {
				sb.append("And Evdr.From_Province = ? ");
				attrs.add("上海");
			}
			if (StringUtils.isNotBlank(fromCity)) {
				sb.append("And Evdr.From_City = ? ");
				attrs.add("上海市");
			}
		}
		if ("30".equals(paymentType)) {
			sb.append("And Evdr.Service = ? ");
			attrs.add("20");
		} else if ("60".equals(paymentType)) {
			sb.append("And Evdr.Service = ? ");
			attrs.add("30");
		}

		sb.append("And Emad.Member_Id = ? ");
		attrs.add(id);

		List<AddressBook> addressBooks = new ArrayList<AddressBook>();
		List<BigDecimal> cuId = getDao().getSQLQueryByList(sb.toString(), attrs, 0, -1);
		if (null != cuId && !cuId.isEmpty()) {
			List tmp = new ArrayList<Long>();
			for (BigDecimal l : cuId) {
				tmp.add(Long.parseLong(l.toString()));
			}
			CommonCriteria crit = new CommonCriteria();
			crit.addIn(FIELD_NAME_BLACK_BOOK_ID, tmp);
			addressBooks = getAddressBookDao().getList(crit, new String[] { "modifyDate" });
		}
		return addressBooks;
	}

	@Override
	public List<AddressBook> getCanUseAddressBook(String id, String type, String fromProvince, String fromCity,
			String fromDistrict, String paymentType) throws CoreException {
		return getCanUseAddressBook(id, type, fromProvince, fromCity, fromDistrict, paymentType, false);
	}

	public ObjectDao<AddressBook> getAddressBookDao() {
		return addressBookDao;
	}

	@Override
	public List<AddressBook> getAddressBookList(CommonCriteria crit) throws CoreException {
		List<AddressBook> addressBooks = getAddressBookDao().getList(crit, new String[] { "modifyDate" });
		return addressBooks;
	}

	@Override
	@Transactional(readOnly = false)
	public List<AddressBook> getAddressBookList(String memberId) throws CoreException {
		StringBuilder sb = new StringBuilder("");
		List<String> attrs = new ArrayList<String>();
		sb.append("Delete From Ec_Member_Address_Book Emad ");
		sb.append("Where Emad.Member_Id = ? ");
		sb.append("And Not Exists (Select Emad.id From Ec_Delivery_Rule Evdr ");
		sb.append("Where Evdr.To_Province = Emad.Province And Evdr.To_City = Emad.City ");
		sb.append("And Evdr.To_District = Emad.District And Emad.Member_Id = ? )");
		attrs.add(memberId);
		attrs.add(memberId);
		jdbcTemplate.update(sb.toString(), attrs.toArray());
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		List<AddressBook> addressBooks = getAddressBookDao().getList(crit, new String[] { "modifyDate" });
		return addressBooks;
	}

	// =========================== Bonus Start ===========================

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#getAvailableBonus(java.lang.String, java.math.BigDecimal)
	 */
	@Override
	@Transactional(readOnly = false)
	public ArrayList<String> getAvailableBonus(String memberId, BigDecimal useBonus) throws Exception {
		// 查询效期内的购物金
		Map<String, Serializable> attrs = new HashMap<String, Serializable>();
		attrs.put(FIELD_NAME_MEMBER_ID, memberId);
		attrs.put("nowDate", DateUtil.getToday().getTime());

		List<Bonus> bonusList = null;
		bonusList = getBalanceDao().getNameQuery("Bonus.getDatelineBonus", attrs, 0, -1);
		ArrayList<String> availBonus = null;
		if (null != bonusList) {
			BigDecimal tempBonus = new BigDecimal(0.00);
			BigDecimal tempUseBonus = useBonus;
			availBonus = new ArrayList<String>();
			StringBuilder sb = new StringBuilder("");
			for (Bonus bonus : bonusList) {
				if (tempUseBonus.compareTo(new BigDecimal(0.00)) > 0) {
					tempBonus = bonus.getTrxAmount().subtract(bonus.getUseBonus()).add(bonus.getRefoundBonus());
					if (tempBonus.compareTo(tempUseBonus) == -1) {// 小於
						availBonus.add(sb.append(bonus.getId()).append(",").append(
								FastDateFormat.getInstance(EcConstant.PATTERN_DATE).format(bonus.getExpireDate())).append(",").append(
								tempBonus).toString());
						tempUseBonus = tempUseBonus.subtract(tempBonus);
					} else if (tempBonus.compareTo(tempUseBonus) >= 0) {// 等於、大於
						availBonus.add(sb.append(bonus.getId()).append(",").append(
								FastDateFormat.getInstance(EcConstant.PATTERN_DATE).format(bonus.getExpireDate())).append(",").append(
								tempUseBonus).toString());
						tempUseBonus = tempUseBonus.subtract(tempUseBonus);
					}
					sb.setLength(0);
				}
			}
			// update bonus資料
			String[] tempBonusData;
			Bonus bonus;
			for (int i = 0; i < availBonus.size(); i++) {
				tempBonusData = availBonus.get(i).split(",");
				bonus = getBonusDao().get(Long.parseLong(tempBonusData[0]));
				bonus.setUseBonus(bonus.getUseBonus().add(new BigDecimal(tempBonusData[2])));
				saveOrUpdateBonus(bonus);
			}
		}
		return availBonus;
	}

	@Override
	public Balance getBalance(String memberId) throws CoreException {
		return getBalanceDao().get(memberId);
	}

	public ObjectDao<Balance> getBalanceDao() {
		return balanceDao;
	}

	@Override
	public BlackList getBlackList(int blackListId) throws CoreException {
		return getBlackListDao().get(blackListId);
	}

	public ObjectDao<BlackList> getBlackListDao() {
		return blackListDao;
	}

	@Override
	public List<BlackList> getBlackLists(CommonCriteria crit) throws CoreException {
		List<BlackList> blackLists = getBlackListDao().getList(crit, null);
		return blackLists;
	}

	@Override
	public Bonus getBonus(Long id) throws CoreException {
		return getBonusDao().get(id);
	}

	public ObjectDao<Bonus> getBonusDao() {
		return bonusDao;
	}

	@Override
	public List<Bonus> getBonusList(CommonCriteria crit, String[] sortBonus) throws CoreException {
		List<Bonus> bonusList = getBonusDao().getList(crit, sortBonus);
		return bonusList;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#ftPwd(java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member getFtMemberPwd(String loginId, String email) throws CoreException {

		Member member = getMemberByLoginId(loginId);
		try {
			if (null != member) {
				// 忘记密码次数+1
				member.setFgPwdCount(member.getFgPwdCount() + 1);
				member.setForgetPwdToken(Long.toString(new Date().getTime()));
				member = super.getDao().update(member);
				// 寄送重设密码通知信函
				Map<String, Object> contentMap = new HashMap<String, Object>();
				StringBuilder urllink = new StringBuilder("");
				contentMap.put("loginId", member.getLoginId());
				contentMap.put("basehref", "http://" + member.getDomainSrc());
				contentMap.put("contextpath", ServerValue.getFrontContextPath());
				contentMap.put("customerFax", ServerValue.getCustomerFax());
				contentMap.put("customerTel", ServerValue.getCustomerTel());
				urllink.append(ServerValue.getFrontHostname() + ServerValue.getFrontContextPath()).append(
						"/forgetpwdchange.do?id=").append(
						PasswordUtils.encodePassword(member.getLoginId() + "-" + member.getForgetPwdToken(), null));
				contentMap.put("urllink", urllink.toString());
				Mail mail = velocityService.formatToMail("member.ftPwdInformMail", contentMap);
				mail.setTo(email);
				mail.setFrom(mailFrom);
				mailService.save(mail);
				urllink.setLength(0);

			} else {
				return null;
			}
		} catch (Exception e) {
			return null;
		}
		return member;
	}

	@Override
	@Transactional(readOnly = false)
	public Member getFtMemberPwdmobile(Member member, String mobile) throws CoreException {
		try {
			if (null != member) {
				// 忘记密码次数 30分钟内重按, 校验码相同不计次数, 但 简讯/邮件 重发
				if (member.getLastMobileForgetPwdDate() == null || StringUtils.isBlank(member.getActivateMobileToken())
						|| !member.getLastMobileForgetPwdDate().after(DateUtil.incrementMinutes(-30).getTime())) {
					member.setFgPwdCount(member.getFgPwdCount() + 1);
					member.setActivateMobileToken(generateCode(8));
					member.setLastMobileForgetPwdDate(new Date());
					member.setMobileForgetPwdCount(member.getMobileForgetPwdCount() + 1);
					member = super.getDao().update(member);
				} else {
					member.setFgPwdCount(member.getFgPwdCount() + 1);
					member.setMobileForgetPwdCount(member.getMobileForgetPwdCount() + 1);
					member = super.getDao().update(member);
				}
				// 发送验证简讯
				smsService.sendSms(member.getMobile(), "您好，欢迎使用手机找回密码。您的校验码为" + member.getActivateMobileToken()
						+ "，请输入校验码完成验证。如非本人操作，请致电耀点100客服400-1168-100", null);
				// 寄送重设密码简讯已发送通知信函
				Map<String, Object> contentMap = new HashMap<String, Object>();
				StringBuilder urllink = new StringBuilder("");
				contentMap.put("loginId", member.getLoginId());
				contentMap.put("basehref", "http://" + member.getDomainSrc());
				contentMap.put("contextpath", ServerValue.getFrontContextPath());
				urllink.append(ServerValue.getFrontHostname() + ServerValue.getFrontContextPath()).append(
						"/forgetpwdmobilecheck.do?loginID=").append(PasswordUtils.encodePassword(member.getLoginId(), null));
				contentMap.put("urllink", urllink.toString());
				Mail mail = velocityService.formatToMail("member.ftPwdMobileMail", contentMap);
				mail.setTo(member.getSendEmail());
				mail.setFrom(mailFrom);
				mailService.save(mail);
			} else {
				return null;
			}
		} catch (Exception e) {
			return null;
		}
		return member;
	}

	public ObjectDao<ImageValid> getImageValidDao() {
		return imageValidDao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#getLastExpireBonus(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public String getLastExpireBonus(String memberId) throws CoreException {
		Map<String, Serializable> attrs = new HashMap<String, Serializable>();
		attrs.put(FIELD_NAME_MEMBER_ID, memberId);
		attrs.put("nowDate", DateUtil.getToday().getTime());
		List<Bonus> bonusList = getBalanceDao().getNameQuery("Bonus.getLastExpireBonus", attrs, 0, -1);
		if (bonusList.isEmpty()) {
			return null;
		}
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		String date = null;
		BigDecimal amount = BigDecimal.ZERO;
		for (Bonus b : bonusList) {
			if (StringUtils.isBlank(date)) {
				date = dateFormat.format(b.getExpireDate());
				amount = b.getTrxAmount().subtract(b.getUseBonus()).add(b.getRefoundBonus());
				continue;
			}
			if (!date.equals(dateFormat.format(b.getExpireDate()))) {
				break;
			}
			amount = amount.add(b.getTrxAmount().subtract(b.getUseBonus()).add(b.getRefoundBonus()));
		}
		return date + "@" + amount.toString();
	}

	/**
	 * 取得上次登入成功記錄
	 * 
	 * @param loginId
	 * @return
	 * @throws CoreException
	 */
	@Override
	public LoginHistory getLastLoginHistory(String loginId) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("loginId", loginId);
		List<LoginHistory> loginHistorys = getLoginHistoryDao().getList(crit, new String[] { "loginTime asc" });
		if (null == loginHistorys || loginHistorys.size() == 0) {
			return null;
		}
		return loginHistorys.get(0);
	}

	public ObjectDao<LoginHistory> getLoginHistoryDao() {
		return loginHistoryDao;
	}

	// =========================== LoginHistory Start ===========================
	@Override
	public int getLoginHistorySize(String loginId, Date startLoginTime, Date endLoginTime) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("loginId", loginId);
		// default 目前的時間，及半個小時前的時間
		Date currentDate = new Date();
		if (startLoginTime == null && endLoginTime == null) {
			crit.addGe("loginTime", DateUtils.addMinutes(currentDate, -30));
			crit.addLe("loginTime", currentDate);
		}
		if (startLoginTime != null && endLoginTime != null) {
			crit.addGe("loginTime", startLoginTime);
			crit.addLe("loginTime", endLoginTime);
		}
		int loginCount = getLoginHistoryDao().getListSize(crit).intValue();
		return loginCount;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#getMemberByEmail(java.lang.String)
	 */
	@Override
	public Member getMemberByEmail(String email) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("email", email);
		crit.addRlike("domainSrc", "%.yaodian100.com");
		List<Member> members = getList(0, -1, crit, null);
		if (members.size() >= 1) {
			for (Member m : members) {
				if (!ServerValue.getTrustMembers().contains(m.getApplySource())) {
					return m;
				}
			}
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#getMemberByLoginId(java.lang.String)
	 */
	@Override
	public Member getMemberByLoginId(String loginId) throws CoreException {
		return getMemberByLoginId(loginId, "");
	}

	@Override
	public Member getMemberByLoginId(String loginId, String domainSrc) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("loginId", loginId);
		if (domainSrc.endsWith("yaodian100.com") || StringUtils.isBlank(domainSrc)) {
			crit.addRlike("domainSrc", "%.yaodian100.com");
		} else {
			crit.addEq("domainSrc", domainSrc);
		}
		List<Member> members = getList(0, -1, crit, new String[] { "modifyDate desc" });
		if (members.size() >= 1) {
			return members.get(0);
		} else {
			return null;
		}
	}

	@Override
	public Member getMemberByMobile(String mobile) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("mobile", mobile);
		crit.addRlike("domainSrc", "%.yaodian100.com");
		List<Member> members = getList(0, -1, crit, new String[] { "modifyDate desc" });
		if (members.size() >= 1) {
			for (Member m : members) {
				if (!ServerValue.getTrustMembers().contains(m.getApplySource())) {
					return m;
				}
			}
		}
		return null;
	}

	public ObjectDao<ViewWishList> getViewWishListDao() {
		return viewWishListDao;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.yaodian100.ec.member.service.MemberService#getWishLists(com.yaodian100.core.common.dao.impl.CommonCriteria)
	 */
	@Override
	public List<ViewWishList> getViewWishLists(int firstResult, int maxResults, CommonCriteria criteria,
			String[] sortOrder) throws CoreException {
		List<ViewWishList> viewWishList = getViewWishListDao().getListPageable(criteria, new String[] { "createDate" },
				firstResult, maxResults);
		return viewWishList;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.yaodian100.ec.member.service.MemberService#getViewWishListSize(com.yaodian100.core.common.dao.impl.CommonCriteria
	 * )
	 */
	@Override
	public Number getViewWishListSize(CommonCriteria criteria) throws CoreException {
		return getViewWishListDao().getListSize(criteria);
	}

	// =========================== Bonus Start ===========================
	@Override
	public List<VirtualBalance> getVirtualBalance(String memberId) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		crit.addEq("type", VirtualBalancePayType.VirtualBalance.getValue());
		List<VirtualBalance> virtualBalances = getVirtualBalanceDao().getList(crit, null);
		return virtualBalances;
	}

	@Override
	public List<VirtualBalance> getGiftcardBalance(String memberId) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		crit.addEq("type", VirtualBalancePayType.GiftcardBalance.getValue());
		List<VirtualBalance> giftcardBalances = getVirtualBalanceDao().getList(crit, null);
		return giftcardBalances;
	}

	@Override
	public List<VirtualBalance> getGiftcardBalanceByPage(String memberId, SimplePager pager) throws Exception {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		crit.addEq("type", VirtualBalancePayType.GiftcardBalance.getValue());

		List<VirtualBalance> giftcardBalances = getVirtualBalanceDao().getListPageable(crit,
				new String[] { "trxDate desc" }, pager.getCurrentPage() * pager.getPageRecord(), pager.getPageRecord());

		return giftcardBalances;
	}

	@Override
	public long getGiftcardBalanceSize(String memberId) throws Exception {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		crit.addEq("type", VirtualBalancePayType.GiftcardBalance.getValue());
		long count = getVirtualBalanceDao().getListSize(crit).longValue();

		return count;
	}

	public ObjectDao<VirtualBalance> getVirtualBalanceDao() {
		return virtualBalanceDao;
	}

	@Override
	public List<VirtualBalance> getVirtualBalanceList(int firstResult, int maxResults, CommonCriteria criteria,
			String[] sortOrder) throws CoreException {
		List<VirtualBalance> virtualBalanceList = getVirtualBalanceDao().getListPageable(criteria, sortOrder, firstResult,
				maxResults);
		return virtualBalanceList;
	}

	@Override
	public VirtualBalance updateVirtualBalanceDate(String trxTypeId, String memberId, Date date) {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		crit.addEq("trxTypeId", trxTypeId);
		crit.addEq("type", VirtualBalancePayType.VirtualBalance.getValue());
		List<VirtualBalance> virtualBalances = getVirtualBalanceDao().getList(crit, null);
		if (null != virtualBalances && virtualBalances.size() > 0) {
			VirtualBalance vb = virtualBalances.get(0);
			vb.setApproveDate(date);
			getVirtualBalanceDao().update(vb);
			return vb;
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.yaodian100.ec.member.service.MemberService#getVirtualBalanceSize(com.yaodian100.core.common.dao.impl.CommonCriteria
	 * )
	 */
	@Override
	public Number getVirtualBalanceSize(CommonCriteria criteria) throws CoreException {
		return getVirtualBalanceDao().getListSize(criteria);
	}

	// =========================== Init ===========================

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#getWaitStartBonus(java.lang.String)
	 */
	@Override
	public String getWaitStartBonus(String memberId) throws CoreException {
		Map<String, Serializable> attrs = new HashMap<String, Serializable>();
		attrs.put(FIELD_NAME_MEMBER_ID, memberId);
		attrs.put("nowDate", DateUtil.getToday().getTime());
		List bonusList = getBalanceDao().getNameQuery("Bonus.getWaitStartBonus", attrs, 0, -1);
		if (null == bonusList.get(0)) {
			return "0";
		}
		return bonusList.get(0).toString();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#getWishList(java.io.Serializable)
	 */
	@Override
	public WishList getWishList(Serializable id) throws CoreException {
		return getWishListDao().get(id);
	}

	public ObjectDao<WishList> getWishListDao() {
		return wishListDao;
	}

	// =========================== Member Start ===========================
	@Override
	public boolean isActived(String memberId) throws CoreException {
		Member member = getDao().get(memberId);
		return member.getActiveDate() == null ? false : true;
	}

	@Override
	public boolean isEmailExist(String email) throws CoreException {
		return isEmailExist(email, null);
	}

	private boolean isEmailExist(String email, Member member) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("email", email);
		// 信任登入會員
		if (null != member && ServerValue.getTrustMembers().contains(member.getApplySource())) {
			crit.addEq("applySource", member.getApplySource());
			int num = getDao().getListSize(crit).intValue();
			if (num > 0) {
				return true;
			} else {
				return false;
			}
		}
		// 本站会员, 含非会员
		List<Member> memberList = getDao().getList(crit, null);
		if (null == memberList || memberList.isEmpty()) {
			return false;
		}
		for (Member m : memberList) {
			if (!ServerValue.getTrustMembers().contains(m.getApplySource())) {
				return true;
			}
		}
		return false;
	}

	@Override
	public boolean isImageValid(ImageValid imageValid) throws CoreException {
		ImageValid temp = imageValidDao.get(imageValid.getId());
		if (!temp.getValidData().toUpperCase().equals(imageValid.getValidData().toUpperCase())) {
			throw new CoreException("图片验证失败");
		}
		return true;
	}

	@Override
	public boolean isLoginExist(String loginId) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("loginId", loginId.trim());
		int num = getDao().getListSize(crit).intValue();
		if (num > 0) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public boolean isMobileExist(String mobile, Member member) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq("mobile", mobile);
		// 信任登入會員
		if (null != member && ServerValue.getTrustMembers().contains(member.getApplySource())) {
			crit.addEq("applySource", member.getApplySource());
			int num = getDao().getListSize(crit).intValue();
			if (num > 0) {
				return true;
			} else {
				return false;
			}
		}
		// 本站会员, 含非会员
		List<Member> memberList = getDao().getList(crit, null);
		if (null == memberList || memberList.isEmpty()) {
			return false;
		}
		for (Member m : memberList) {
			if (!ServerValue.getTrustMembers().contains(m.getApplySource())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 会员登入
	 * 
	 * @param properties
	 * @return
	 * @throws CoreException
	 */
	@Override
	@Transactional(readOnly = false)
	public Member login(Properties properties) throws CoreException {
		try {
			String loginId = null;
			String pwd = null;
			if (properties != null) {
				if (properties.getProperty("loginId") != null) {
					loginId = properties.getProperty("loginId").toString();
				}
				if (properties.get("pwd") != null) {
					pwd = passwordEncoder.encodePassword(properties.getProperty("pwd"), null);
				}
			}
			// TODO 帳密不正確or會員被鎖定都先return null
			Member member = checkLoginData(loginId);
			if (member != null && !member.getStatus().equals("10")) {// 非登入鎖定狀態,檢查帳密是否正確
				if (member.getPwd().equals(pwd)) {
					// 判断balance的bonus资料今天是否被更新过，若无则重新计算今日bonus资料
					if (null == member.getBalance().getBonusLastUpdTime()
							|| !DateUtils.isSameDay(member.getBalance().getBonusLastUpdTime(), DateUtil.getToday().getTime())) {
						reCalculateBalance(member.getMemberId());
					}
				}
				return member;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 会员登入
	 * 
	 * @param properties
	 * @return
	 * @throws CoreException
	 */
	@Override
	@Transactional(readOnly = false)
	public Member loginPwdCheck(String pwd, Member member) throws CoreException {
		try {
			if (pwd != null) {
				pwd = passwordEncoder.encodePassword(pwd, null);
			}
			if (member.getPwd().equals(pwd)) {
				// 判断balance的bonus资料今天是否被更新过，若无则重新计算今日bonus资料
				if (null == member.getBalance().getBonusLastUpdTime()
						|| !DateUtils.isSameDay(member.getBalance().getBonusLastUpdTime(), DateUtil.getToday().getTime())) {
					member.setBalance(reCalculateBalance(member.getMemberId()));
					// // 產生此會員的訂單資料
					// generateOrderService.generateMemberOrderPage(member.getMemberId());
				}
				return member;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	@Transactional(readOnly = false)
	public void checkBalance(Member member) throws Exception {
		if (null != member) {
			// 判断balance的bonus资料今天是否被更新过，若无则重新计算今日bonus资料
			if (null == member.getBalance().getBonusLastUpdTime()
					|| !DateUtils.isSameDay(member.getBalance().getBonusLastUpdTime(), DateUtil.getToday().getTime())) {
				member.setBalance(reCalculateBalance(member.getMemberId()));
			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public Balance newBalance(Member member) {
		// 新增balance资料
		Balance balance = new Balance();
		balance.setMemberID(member.getMemberId());
		balance.setBonusBalance(new BigDecimal(0));
		balance.setGiftcardBalance(new BigDecimal(0));
		balance.setPointBalance(new BigDecimal(0));
		balance.setVirtualBalance(new BigDecimal(0));
		return getBalanceDao().save(balance);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#pwdCheck(java.lang.String,
	 * com.yaodian100.ec.member.entity.Member)
	 */
	@Override
	public boolean pwdCheck(String pwd, Member member) throws CoreException {
		if (StringUtils.isNotBlank(pwd)) {
			return member.getPwd().equals(passwordEncoder.encodePassword(pwd, null));
		}
		return false;
	}

	// =========================== BlackList Start ===========================
	@Override
	@Transactional(readOnly = false)
	public BlackList quickUnLock(BlackList blackList) throws CoreException {
		blackList.setUnBlockDate(DateUtil.getToday().getTime());
		blackList.setBlockStatus(BLACK_BOOK_BLOCK_STATUS_NO);// 停用
		blackList = getBlackListDao().update(blackList);
		// update member block status
		updateBlockStatus(blackList);
		return blackList;
	}

	@Override
	@Transactional(readOnly = false)
	public Balance reCalculateBalance(String memberId) throws Exception {
		// 查询效期内的购物金
		Map<String, Serializable> attrs = new HashMap<String, Serializable>();
		attrs.put(FIELD_NAME_MEMBER_ID, memberId);
		attrs.put("nowDate", DateUtil.getToday().getTime());
		List<Bonus> bonusList = null;
		bonusList = getBalanceDao().getNameQuery("Bonus.getDatelineBonus", attrs, 0, -1);

		BigDecimal bonusTotalAmount = new BigDecimal(0);
		if (null != bonusList) {
			for (Bonus tmpBonus : bonusList) {
				bonusTotalAmount = bonusTotalAmount.add(tmpBonus.getTrxAmount().subtract(tmpBonus.getUseBonus()).add(
						tmpBonus.getRefoundBonus()));
			}
		}
		// 查询我的账户余额
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		crit.addEq("type", VirtualBalancePayType.VirtualBalance.getValue());
		List<VirtualBalance> virtualBalanceList = null;
		virtualBalanceList = getVirtualBalanceDao().getList(crit, null);
		BigDecimal virtualBalanceTotalAmount = new BigDecimal(0);
		if (null != virtualBalanceList) {
			for (VirtualBalance tmpVirtualBalance : virtualBalanceList) {
				virtualBalanceTotalAmount = virtualBalanceTotalAmount.add(tmpVirtualBalance.getTrxAmount());
			}
		}
		// 查询我的礼品卡
		crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		crit.addEq("type", VirtualBalancePayType.GiftcardBalance.getValue());
		List<VirtualBalance> giftcardBalanceList = null;
		giftcardBalanceList = getVirtualBalanceDao().getList(crit, null);
		BigDecimal giftcardBalanceTotalAmount = new BigDecimal(0);
		if (null != giftcardBalanceList) {
			for (VirtualBalance tmpgiftcardBalance : giftcardBalanceList) {
				giftcardBalanceTotalAmount = giftcardBalanceTotalAmount.add(tmpgiftcardBalance.getTrxAmount());
			}
		}
		// 更新balance table
		Balance balance = getBalanceDao().get(memberId);
		if (null == balance) {
			balance = new Balance();
			balance.setMemberID(memberId);
		}
		balance.setBonusBalance(bonusTotalAmount);
		balance.setVirtualBalance(virtualBalanceTotalAmount);
		balance.setGiftcardBalance(giftcardBalanceTotalAmount);
		// TODO 客服与问答:两週内已回答數、发问中的商品提问數、已回答的商品提问數、需支付的订单數 暂时写0
		// balance.setAskedProductQuestion(new BigDecimal(0));
		// balance.setOrderToPay(new BigDecimal(0));
		// balance.setRepliedCRM(new BigDecimal(0));
		// balance.setRepliedProductQuestion(new BigDecimal(0));
		balance.setBonusLastUpdTime(DateUtil.getToday().getTime());
		balance = getBalanceDao().saveOrUpdate(balance);
		return balance;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#removeOverdueMember()
	 */
	@Override
	@Transactional(readOnly = false)
	public void removeOverdueMember() {
		CommonCriteria crit = new CommonCriteria();
		crit.addLe("activateExpireDate", new Date());
		crit.addEq("activeDate", null);
		crit.addNe("applySource", "nonmember");
		List<Member> members = getList(0, -1, crit, null);
		for (int i = 0; i < members.size(); i++) {
			Member deletem = members.get(i);
			Balance deleteb = getBalance(deletem.getMemberId());
			getBalanceDao().delete(deleteb);
			getDao().delete(deletem);
		}
	}

	@Override
	@Transactional(readOnly = false)
	public String resendRegActivateMail(Member member, String mail, String password) throws CoreException {
		String type = "resend_";
		if (StringUtils.isNotBlank(mail)) {
			if (!(StringUtils.isNotBlank(password) && member.getPwd().equals(passwordEncoder.encodePassword(password, null)))) {
				return "error";
			}
			if (isEmailExist(mail)) {
				return "exist";
			}
			member.setEmail(mail);
			type = "modify_send_";
		}
		if (null == member.getActivateExpireDate()) {
			member.setActivateExpireDate(DateUtils.addDays(new Date(), 7));
		}
		member.setActivateToken(Long.toString(new Date().getTime()));
		if (StringUtils.isBlank(member.getEmail())) { // 手机注册改用mail激活
			member.setEmail(member.getTempEmail());
			member.setTempEmail(null);
			member.setTempMobile(member.getMobile());
			member.setMobile(null);
			member.setActivateMobileToken(null);
		}
		super.update(member);

		// 重送註冊激活通知信
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("loginId", member.getLoginId());
		contentMap.put("member", member);
		contentMap.put("memberEvent", getMemberEvent(member));
		StringBuilder urllink = new StringBuilder("");
		urllink.append(ServerValue.getFrontHostname() + ServerValue.getFrontContextPath()).append("/regActive.do?code=")
				.append(PasswordUtils.encodePassword(member.getMemberId() + "-" + member.getActivateToken(), null));
		contentMap.put("urllink", urllink.toString());
		contentMap.put("basehref", "http://" + member.getDomainSrc());
		contentMap.put("contextpath", ServerValue.getFrontContextPath());

		Mail mailvm = velocityService.formatToMail("member.registerActivateMail", contentMap);
		mailvm.setTo(member.getEmail());
		mailvm.setFrom(mailFrom);
		mailService.save(mailvm);

		return type + "success";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#resendRegActivateMail(com.yaodian100.ec.member.entity.Member,
	 * java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public String resendRegActivateSMS(Member member, String mobile) throws CoreException {
		if (member.getActivateCount() >= 5) {
			return "error";
		}
		if (StringUtils.isNotBlank(mobile)) {
			if (isMobileExist(mobile, member)) {
				return "exist";
			}
			member.setMobile(mobile);
		}
		// 30分钟内重按, 校验码相同不计次数, 但 简讯/邮件 重发
		if (StringUtils.isBlank(member.getActivateMobileToken())
				|| !member.getModifyDate().after(DateUtil.incrementMinutes(-30).getTime())) {
			member.setActivateMobileToken(generateCode(8));
			member.setActivateCount(member.getActivateCount() + 1);
			super.update(member);
		} else {
			member.setActivateCount(member.getActivateCount() + 1);
			super.update(member);
		}

		// 发送激活简讯
		smsService.sendSms(member.getMobile(), "感谢您注册耀点100！您的校验码为：" + member.getActivateMobileToken()
				+ "，请登录“耀点100”继续完成手机验证。如非本人操作，请致电400-1168-100", null);
		// 寄送註冊手机验证通知信
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("member", member);
		contentMap.put("basehref", "http://" + member.getDomainSrc());
		contentMap.put("contextpath", ServerValue.getFrontContextPath());
		contentMap.put("memberEvent", getMemberEvent(member));
		Mail mail = velocityService.formatToMail("member.registerMobileMail", contentMap);
		mail.setTo(member.getTempEmail());
		mail.setFrom(mailFrom);
		mailService.save(mail);

		return "success";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#returnBonus(java.util.ArrayList)
	 */
	@Override
	public boolean returnBonus(ArrayList<Map> returnBonus, String orderId) throws Exception {
		try {
			if (null != returnBonus) {
				Bonus bonus = null;
				// 是否为我方因素退款
				boolean checkResult = true;
				if (orderId != null) {
					checkResult = checkOrderForUnuse(orderId);
				}
				for (Map btMap : returnBonus) {
					Set ks = btMap.keySet();
					Iterator ksiter = ks.iterator();
					while (ksiter.hasNext()) {
						Long bid = (Long) ksiter.next();
						if (new BigDecimal("0").compareTo((BigDecimal) btMap.get(bid)) == 0) {
							continue;
						}
						bonus = getBonus(bid);

						DateFormat df = new SimpleDateFormat("yyyyMMdd");
						Date todays = df.parse(df.format(new Date()));
						Date todaye = new SimpleDateFormat("yyyyMMddHHmmss").parse(df.format(todays) + "235959");
						if (bonus.getExpireDate().before(DateUtils.addDays(todaye, 3)) && checkResult) {
							// 我方因素取消, 到期日<=系統日+3，原到期日改為：取消隔日＋10
							if (bonus.getTrxAmount().compareTo((BigDecimal) btMap.get(bid)) == 0) {
								bonus.setRefoundBonus(bonus.getRefoundBonus().add((BigDecimal) btMap.get(bid)));
								bonus.setExpireDate(DateUtils.addDays(todaye, 11));
								bonus = saveOrUpdateBonusNotRecalculate(bonus);
							} else { // 只针对退回的购物金延期
								Bonus newBonus = new Bonus();
								newBonus.setDescription(bonus.getDescription());
								newBonus.setMemberId(bonus.getMemberId());
								newBonus.setOrderId(bonus.getOrderId());
								newBonus.setTrxType(bonus.getTrxType());
								newBonus.setTrxAmount((BigDecimal) btMap.get(bid));
								newBonus.setStartDate(todays);// 立即生效
								newBonus.setExpireDate(DateUtils.addDays(todaye, 11));
								newBonus.setTrxDate(new Date());
								saveOrUpdateBonusNotRecalculate(newBonus);
							}
						} else {
							bonus.setRefoundBonus(bonus.getRefoundBonus().add((BigDecimal) btMap.get(bid)));
							bonus = saveOrUpdateBonus(bonus);
						}
					}
				}
			} else {
				return false;
			}
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#returnBonus(java.util.ArrayList)
	 */
	@Override
	public boolean returnBonus(ArrayList<Map> returnBonus) throws Exception {
		return this.returnBonus(returnBonus, null);
	}

	private boolean checkOrderForUnuse(String orderId) throws Exception {
		String sql = "select count(*) from crm_question_ev where question_id in ( "
				+ "select question_id from crm_question_ev where name='orderId' and value=? "
				+ ") and name='cancelReason' and value in('10','20','30') ";
		int cnt = this.jdbcTemplate.queryForInt(sql, orderId);
		return (cnt > 1);
	}

	// =========================== AddressBook Start ===========================
	@Override
	@Transactional(readOnly = false)
	public AddressBook saveAddressBook(AddressBook addressBook) throws CoreException {
		addressBook = getAddressBookDao().save(addressBook);
		return addressBook;
	}

	@Override
	@Transactional(readOnly = false)
	public BlackList saveBlackList(BlackList blackList) throws CoreException {
		blackList = getBlackListDao().save(blackList);
		// update member block status
		updateBlockStatus(blackList);
		return blackList;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#saveFrontendLoginBlackList(java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public BlackList saveFrontendLoginBlackList(String loginId) throws CoreException {
		Member member = getMemberByLoginId(loginId);
		BlackList blackList = new BlackList();
		blackList.setMemberId(member.getMemberId());
		blackList.setBlockStatus(BLACK_BOOK_BLOCK_STATUS_YES);
		blackList.setBlockType("10");
		blackList = saveBlackList(blackList);

		// 更新会员状态
		member.setBlackListId(blackList.getId());
		member.setStatus(blackList.getBlockType());
		member.setUnBlockDate(null);
		member = super.update(member);
		return blackList;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#saveFrontendLoginHistory(java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public LoginHistory saveFrontendLoginHistory(Member member, String clientIp) throws CoreException, ParseException {
		return saveFrontendLoginHistory(member, clientIp, "0");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#saveFrontendLoginHistory(java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public LoginHistory saveFrontendLoginHistory(Member member, String clientIp, String isSuccess) throws CoreException,
			ParseException {
		LoginHistory loginHistory = new LoginHistory();
		loginHistory.setLoginTime(DateUtil.getCurrentTime());
		loginHistory.setLoginId(member.getLoginId());
		loginHistory.setMemberId(member.getMemberId());
		loginHistory.setClientIp(clientIp);
		loginHistory.setIsSuccess(isSuccess);
		loginHistory = saveLoginHistory(loginHistory);
		return loginHistory;
	}

	@Override
	@Transactional(readOnly = false)
	public void checkLoginBonus(Member member, String loginDomain, String cookie) throws ParseException {
		if (null == member.getLastLoginTime()
				|| !DateUtils.isSameDay(member.getLastLoginTime(), DateUtil.getToday().getTime())) {
			member.setLoginCount(1);
		} else {
			member.setLoginCount(member.getLoginCount() + 1);
		}
		update(member);

		Map<String, String> options = new HashMap<String, String>();
		options.put("domain", loginDomain);
		options.put("cookie", cookie);
		Campaign campaign = campaignService.getActiveBonusCampaignByM03(options);
		if (null == campaign) {
			return;
		}

		if (member.getLoginCount() == Integer.parseInt(campaign.getLoginCount())) { // 发送积分
			Bonus bonus = new Bonus();
			bonus.setMemberId(member.getMemberId());
			bonus.setTrxAmount(new BigDecimal(campaign.getGiveBonus()));
			bonus.setTrxType("EVENT_POINT");
			bonus.setTrxDate(new Date());
			bonus.setDescription(campaign.getCampaignName());
			DateFormat df = new SimpleDateFormat("yyyyMMdd");
			bonus.setStartDate(df.parse(df.format(new Date())));// 立即生效
			Date expireDate = df.parse(new SimpleDateFormat("yyyyMM").format(DateUtils.addMonths(bonus.getStartDate(), 13))
					+ "01");// 效期固定到隔年月底
			bonus.setExpireDate(new Date(expireDate.getTime() - 1));
			try {
				bonus = saveOrUpdateBonus(bonus);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/*
	 * 新增一個認證碼
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#saveImageValid(com.yaodian100.ec.member.entity.ImageValid)
	 */
	@Override
	@Transactional(readOnly = false)
	public ImageValid saveImageValid(ImageValid imageValid) throws CoreException {
		imageValidDao.save(imageValid);
		return imageValid;
	}

	@Override
	@Transactional(readOnly = false)
	public Member saveMember(Member entity) throws CoreException {
		return this.saveMember(entity, true);
	}

	@Override
	@Transactional(readOnly = false)
	public LoginHistory saveLoginHistory(LoginHistory loginHistory) throws CoreException {
		return getLoginHistoryDao().save(loginHistory);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#saveMember(com.yaodian100.ec.member.entity.Member)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member saveMember(Member entity, boolean encodePwd) throws CoreException {
		if ("nonmember".equals(entity.getApplySource())) {
			try {
				entity.setActivateExpireDate(new SimpleDateFormat("yyyyMMdd").parse("99991231"));
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			entity.setActivateToken(Long.toString(new Date().getTime()));
		} else {
			if (encodePwd) {
				// 密码加密
				entity.setPwd(passwordEncoder.encodePassword(entity.getPwd(), null));
			}
			entity.setRank("1");
			entity.setStatus("00");

			entity.setActivateExpireDate(new java.sql.Date(DateUtils.addDays(new Date(), 7).getTime()));
			entity.setActivateToken(Long.toString(new Date().getTime()));
		}
		Member member = super.save(entity);

		// 寄送註冊激活通知信
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("loginId", member.getLoginId());
		contentMap.put("member", member);
		contentMap.put("memberEvent", getMemberEvent(member));
		StringBuilder urllink = new StringBuilder("");
		urllink.append(ServerValue.getFrontHostname() + ServerValue.getFrontContextPath()).append("/regActive.do?code=")
				.append(PasswordUtils.encodePassword(member.getMemberId() + "-" + member.getActivateToken(), null));
		contentMap.put("urllink", urllink.toString());
		contentMap.put("basehref", "http://" + member.getDomainSrc());
		contentMap.put("contextpath", ServerValue.getFrontContextPath());

		Mail mail = velocityService.formatToMail("member.registerActivateMail", contentMap);
		mail.setTo(member.getEmail());
		mail.setFrom(mailFrom);
		mailService.save(mail);

		if (!"nonmember".equals(entity.getApplySource())) {
			newBalance(member);
		}
		return member;
	}

	@Override
	@Transactional(readOnly = false)
	public Member saveNonMember(Member entity) throws CoreException {
		entity.setPwd(passwordEncoder.encodePassword(entity.getPwd(), null));
		entity.setRank("1");
		entity.setStatus("00");

		return super.save(entity);
	}

	@Override
	@Transactional(readOnly = false)
	public Member saveMobileMember(Member entity) throws CoreException {
		return this.saveMobileMember(entity, true);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#saveMobileMember(com.yaodian100.ec.member.entity.Member)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member saveMobileMember(Member entity, boolean encodePwd) throws CoreException {
		// 密码加密
		if (encodePwd) {
			entity.setPwd(passwordEncoder.encodePassword(entity.getPwd(), null));
		}
		entity.setRank("1");
		entity.setStatus("00");

		entity.setActivateExpireDate(new java.sql.Date(DateUtils.addDays(new Date(), 7).getTime()));
		entity.setActivateMobileToken(generateCode(8));
		entity.setActivateCount(1);

		Member member = super.save(entity);

		// 发送激活简讯
		smsService.sendSms(member.getMobile(), "感谢您注册耀点100！您的校验码为" + member.getActivateMobileToken()
				+ "，请登录“耀点100”继续完成手机验证。如非本人操作，请致电400-1168-100", null);
		// 寄送註冊手机验证通知信
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("member", member);
		contentMap.put("basehref", "http://" + member.getDomainSrc());
		contentMap.put("contextpath", ServerValue.getFrontContextPath());
		contentMap.put("memberEvent", getMemberEvent(member));
		Mail mail = velocityService.formatToMail("member.registerMobileMail", contentMap);
		mail.setTo(member.getTempEmail());
		mail.setFrom(mailFrom);
		mailService.save(mail);

		newBalance(member);
		return member;
	}

	// =========================== Balance Start ===========================
	@Override
	@Transactional(readOnly = false)
	public Balance saveOrUpdateBalance(Balance balance) throws CoreException {
		return balanceDao.saveOrUpdate(balance);
	}

	@Override
	@Transactional(readOnly = false)
	public Bonus saveOrUpdateBonusNotRecalculate(Bonus bonus) {
		bonus = getBonusDao().saveOrUpdate(bonus);
		return bonus;
	}

	@Override
	@Transactional(readOnly = false)
	public Bonus saveOrUpdateBonus(Bonus bonus) throws Exception {
		bonus = getBonusDao().saveOrUpdate(bonus);
		// 重新计算balance内购物金资料
		Balance balance = reCalculateBalance(bonus.getMemberId());
		return bonus;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#saveOrUpdateBonusBatch(java.util.List)
	 */
	@Override
	@Transactional(readOnly = false)
	public boolean saveOrUpdateBonusBatch(List<Bonus> bonusList) throws Exception {
		try {
			getBonusDao().saveOrUpdateBatch(bonusList);
			// 更新balance资料
			for (Bonus bonus : bonusList) {
				reCalculateBalance(bonus.getMemberId());
			}
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	@Override
	@Transactional(readOnly = false)
	public VirtualBalance saveOrUpdateVirtualBalance(VirtualBalance virtualBalance) throws Exception {
		VirtualBalance newVB = getVirtualBalanceDao().saveOrUpdate(virtualBalance);
		// 重新计算balance内账户余额资料
		Balance balance = reCalculateBalance(newVB.getMemberId());
		if (virtualBalance.getType().equals(VirtualBalancePayType.VirtualBalance.getValue())) {
			newVB.setSummaryAmount(balance.getVirtualBalance());
			getVirtualBalanceDao().saveOrUpdate(newVB);
		}
		if (virtualBalance.getType().equals(VirtualBalancePayType.GiftcardBalance.getValue())) {
			newVB.setSummaryAmount(balance.getGiftcardBalance());
			getVirtualBalanceDao().saveOrUpdate(newVB);
		}
		return newVB;

	}

	// =========================== WishList Start ===========================
	@Override
	@Transactional(readOnly = false)
	public WishList saveWishList(WishList wishList) throws CoreException {
		return getWishListDao().save(wishList);
	}

	@Override
	@Transactional(readOnly = false)
	public String sendDeleteMobileActivateSms(Member member, String password) throws CoreException {
		if (member.getMobileModifyCount() >= 10) {
			return "error";
		}
		String type = "resend_";
		if (StringUtils.isNotBlank(password)) {
			type = "delete_send_";
			if (!member.getPwd().equals(passwordEncoder.encodePassword(password, null))) {
				return "pwd_error";
			}
		}

		// 30分钟内重按, 校验码相同不计次数, 但 简讯/邮件 重发
		if (member.getLastMobileModifyDate() == null || StringUtils.isBlank(member.getActivateMobileToken())
				|| !member.getLastMobileModifyDate().after(DateUtil.incrementMinutes(-30).getTime())) {
			member.setActivateMobileToken(generateCode(8));
			member.setLastMobileModifyDate(new Date());
			member.setMobileModifyCount(member.getMobileModifyCount() + 1);
			super.update(member);
		} else {
			member.setMobileModifyCount(member.getMobileModifyCount() + 1);
			super.update(member);
		}

		// 发送激活简讯
		smsService.sendSms(member.getMobile(), "您好，您的校验码为" + member.getActivateMobileToken()
				+ "，请输入校验码进行手机验证，以完成删除手机号码。如非本人操作，请致电耀点100客服400-1168-100", null);
		// 寄送修改手机通知信
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("member", member);
		contentMap.put("basehref", "http://" + member.getDomainSrc());
		contentMap.put("contextpath", ServerValue.getFrontContextPath());
		contentMap.put("expiredate", new SimpleDateFormat("yyyy-MM-dd").format(member.getActivateExpireDate()));
		StringBuilder urllink = new StringBuilder("");
		urllink.append(ServerValue.getFrontHostname() + ServerValue.getFrontContextPath()).append(
				"/member/deletemobilecheck.do?ccode=").append(PasswordUtils.encodePassword(member.getLoginId(), null));
		contentMap.put("urllink", urllink.toString());

		Mail mail;
		mail = velocityService.formatToMail("member.deleteMobileMail", contentMap); // modify mobile
		mail.setTo(member.getSendEmail());
		mail.setFrom(mailFrom);
		mailService.save(mail);
		return type + "success";
	}

	@Override
	@Transactional(readOnly = false)
	public void sendForgetPwdModifyOkMail(String loginId, String ccode) throws CoreException {
		// 寄送修改密碼成功信函
		Member member = getMemberByLoginId(loginId);
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("loginId", member.getLoginId());
		contentMap.put("basehref", "http://" + member.getDomainSrc());
		contentMap.put("customerFax", ServerValue.getCustomerFax());
		contentMap.put("customerTel", ServerValue.getCustomerTel());
		contentMap.put("contextpath", ServerValue.getFrontContextPath());
		Mail mail = velocityService.formatToMail("member.ForgetPwdModifyOkMail", contentMap);
		if (ccode.length() == 8) { // 手机找回
			member.setActivateMobileToken(null);
			getDao().update(member);
			mail.setTo(member.getSendEmail());
		} else { // email找回
			member.setForgetPwdToken(null);
			getDao().update(member);
			mail.setTo(member.getEmail());
		}
		mail.setFrom(mailFrom);
		mailService.save(mail);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#sendModifyActivateMail(com.yaodian100.ec.member.entity.Member,
	 * java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public String sendModifyActivateMail(String loginId, String mail, String password) throws CoreException {
		Member member = getMemberByLoginId(loginId);
		String type = "resend_";
		if (StringUtils.isNotBlank(mail)) {
			if ((!ServerValue.getTrustMembers().contains(member.getApplySource())) // 信任登入会员不检查密码
					&& !(StringUtils.isNotBlank(password) && member.getPwd().equals(
							passwordEncoder.encodePassword(password, null)))) {
				return "pwd_error";
			}
			type = "modify_send_";
		} else {
			mail = member.getTempEmail();
		}
		if (isEmailExist(mail, member)) {
			return "mail_exist";
		}
		member.setTempEmail(mail);
		member.setActivateToken(Long.toString(new Date().getTime()));
		super.update(member);

		// 寄送激活通知信
		Map<String, Object> contentMap = new HashMap<String, Object>();
		StringBuilder urllink = new StringBuilder("");
		urllink.append(ServerValue.getFrontHostname() + ServerValue.getFrontContextPath()).append(
				"/member/modifyActive.do?code=").append(
				PasswordUtils.encodePassword(member.getMemberId() + "-" + member.getActivateToken(), null));
		Date date = new Date();
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		contentMap.put("customerFax", ServerValue.getCustomerFax());
		contentMap.put("customerTel", ServerValue.getCustomerTel());
		contentMap.put("date", dateFormat.format(date));
		contentMap.put("urllink", urllink.toString());
		contentMap.put("basehref", "http://" + member.getDomainSrc());
		contentMap.put("contextpath", ServerValue.getFrontContextPath());
		contentMap.put("omail", member.getEmail());
		contentMap.put("nmail", member.getTempEmail());
		contentMap.put("loginId", member.getLoginId());
		Mail mailvm;
		if (StringUtils.isBlank(member.getEmail()) || "xx".equals(member.getEmail())) {
			mailvm = velocityService.formatToMail("member.activateNewMail", contentMap);
		} else {
			mailvm = velocityService.formatToMail("member.modifyActivateMail", contentMap);
		}
		mailvm.setTo(member.getTempEmail());
		mailvm.setFrom(mailFrom);
		mailService.save(mailvm);

		return type + "success";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.yaodian100.ec.member.service.MemberService#sendModifyMobileActivateSms(com.yaodian100.ec.member.entity.Member,
	 * java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public String sendModifyMobileActivateSms(Member member, String mobile, String password, boolean needPwd)
			throws CoreException {
		if (member.getMobileModifyCount() >= 10) {
			return "error";
		}
		String type = "resend_";
		if (StringUtils.isNotBlank(mobile)) {
			if (needPwd) {
				if (!(StringUtils.isNotBlank(password) && member.getPwd()
						.equals(passwordEncoder.encodePassword(password, null)))) {
					return "pwd_error";
				}
			}
			if (isMobileExist(mobile, member)) {
				return "mobile_exist";
			}
			member.setTempMobile(mobile);
			type = "modify_send_";
		} else {
			if (isMobileExist(member.getTempMobile(), member)) {
				return "mobile_exist";
			}
		}
		// 30分钟内重按, 校验码相同不计次数, 但 简讯/邮件 重发
		if (member.getLastMobileModifyDate() == null || StringUtils.isBlank(member.getActivateMobileToken())
				|| !member.getLastMobileModifyDate().after(DateUtil.incrementMinutes(-30).getTime())) {
			member.setActivateMobileToken(generateCode(8));
			member.setLastMobileModifyDate(new Date());
			member.setMobileModifyCount(member.getMobileModifyCount() + 1);
			super.update(member);
		} else {
			member.setMobileModifyCount(member.getMobileModifyCount() + 1);
			super.update(member);
		}

		// 发送激活简讯
		smsService.sendSms(member.getTempMobile(), "您好，您的校验码为" + member.getActivateMobileToken()
				+ "，请输入校验码进行手机验证，以完成更改手机号码。如非本人操作，请致电耀点100客服400-1168-100", null);
		// 寄送修改手机通知信
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("member", member);
		contentMap.put("basehref", "http://" + member.getDomainSrc());
		contentMap.put("contextpath", ServerValue.getFrontContextPath());
		// contentMap.put("expiredate", new SimpleDateFormat("yyyy-MM-dd").format(member.getActivateExpireDate()));
		StringBuilder urllink = new StringBuilder("");
		urllink.append(ServerValue.getFrontHostname() + ServerValue.getFrontContextPath()).append(
				"/member/modifymobilecheck.do?ccode=").append(PasswordUtils.encodePassword(member.getLoginId(), null));
		contentMap.put("urllink", urllink.toString());

		Mail mail;
		if (StringUtils.isBlank(member.getMobile())) {
			mail = velocityService.formatToMail("member.newMobileMail", contentMap); // new mobile
		} else {
			mail = velocityService.formatToMail("member.modifyMobileMail", contentMap); // modify mobile
		}
		mail.setTo(member.getSendEmail());
		mail.setFrom(mailFrom);
		mailService.save(mail);
		return type + "success";
	}

	@Override
	@Transactional(readOnly = false)
	public void sendModifyPwdOkMail(String loginId) throws CoreException {
		// 寄送修改密碼成功信函
		Member member = getMemberByLoginId(loginId);
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("loginId", member.getLoginId());
		contentMap.put("basehref", "http://" + member.getDomainSrc());
		contentMap.put("contextpath", ServerValue.getFrontContextPath());
		contentMap.put("customerFax", ServerValue.getCustomerFax());
		contentMap.put("customerTel", ServerValue.getCustomerTel());
		Date date = new Date();
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		contentMap.put("date", dateFormat.format(date));
		Mail mail = velocityService.formatToMail("member.ModifyPwdOkMail", contentMap);
		mail.setTo(member.getSendEmail());
		mail.setFrom(mailFrom);
		mailService.save(mail);
	}

	public void setAddressBookDao(ObjectDao<AddressBook> addressBookDao) {
		this.addressBookDao = addressBookDao;
	}

	public void setBalanceDao(ObjectDao<Balance> balanceDao) {
		this.balanceDao = balanceDao;
	}

	public void setBlackListDao(ObjectDao<BlackList> blackListDao) {
		this.blackListDao = blackListDao;
	}

	public void setBonusDao(ObjectDao<Bonus> bonusDao) {
		this.bonusDao = bonusDao;
	}

	public void setImageValidDao(ObjectDao<ImageValid> imageValidDao) {
		this.imageValidDao = imageValidDao;
	}

	public void setLoginHistoryDao(ObjectDao<LoginHistory> loginHistoryDao) {
		this.loginHistoryDao = loginHistoryDao;
	}

	/**
	 * @param mailFrom the mailFrom to set
	 */
	public void setMailFrom(String mailFrom) {
		this.mailFrom = mailFrom;
	}

	public void setMailService(MailService mailService) {
		this.mailService = mailService;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#setMemberActive(java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member setMemberActive(String memberId, String activeToken) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		List<Member> members = getList(0, -1, crit, null);
		if (members.size() == 1) {
			Member member = members.get(0);
			Date activeD = new Date();
			if ((activeD.getTime() < member.getActivateExpireDate().getTime())
					&& member.getActivateToken().equals(activeToken)) {

				// 寄送注册成功信函
				Map<String, Object> contentMap = new HashMap<String, Object>();
				contentMap.put("loginId", member.getLoginId());
				contentMap.put("basehref", "http://" + member.getDomainSrc());
				contentMap.put("contextpath", ServerValue.getFrontContextPath());
				Mail mail = velocityService.formatToMail("member.registerSuccessMail", contentMap);
				mail.setTo(member.getEmail());
				mail.setFrom(mailFrom);
				mailService.save(mail);

				member.setActiveDate(activeD);
				member.setActivateToken(null);
				if ("nonmember".equals(member.getApplySource())) {
					member.setApplySource("yaodian100");
				}
				memberEventService.checkActiveBonus_Coupon(member);
				super.update(member);
				return member;
			}
		}
		return null;
	}

	/**
	 * @param memberEventService the memberEventService to set
	 */
	public void setMemberEventService(MemberEventService memberEventService) {
		this.memberEventService = memberEventService;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#setMobileMemberActive(java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member setMobileMemberActive(String loginId, String ccode) throws CoreException {
		Member member = getMemberByLoginId(loginId);
		Date activeD = new Date();
		if ((activeD.getTime() < member.getActivateExpireDate().getTime())
				&& member.getActivateMobileToken().equalsIgnoreCase(ccode)) {

			// 寄送注册成功信函
			Map<String, Object> contentMap = new HashMap<String, Object>();
			contentMap.put("loginId", member.getLoginId());
			contentMap.put("basehref", "http://" + member.getDomainSrc());
			contentMap.put("contextpath", ServerValue.getFrontContextPath());
			Mail mail = velocityService.formatToMail("member.mobileregisterSuccessMail", contentMap);
			mail.setTo(member.getTempEmail());
			mail.setFrom(mailFrom);
			mailService.save(mail);

			member.setActiveDate(activeD);
			member.setActivateMobileToken(null);
			memberEventService.checkActiveBonus_Coupon(member);
			super.update(member);
			return member;
		}
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#setModifyMobileActive(com.yaodian100.ec.member.entity.Member,
	 * java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member setModifyMobileActive(Member member) throws CoreException {
		member.setActivateMobileToken(null);
		if (!isMobileExist(member.getTempMobile(), member)) {
			member.setMobile(member.getTempMobile());
			member.setTempMobile(null);
			super.update(member);
			checkCompleteInfoBonus(member);
			return member;
		}
		member.setTempMobile(null);
		super.update(member);
		return null;
	}

	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	/**
	 * @param smsService the smsService to set
	 */
	public void setSmsService(SmsService smsService) {
		this.smsService = smsService;
	}

	public void setVelocityService(TemplateService velocityService) {
		this.velocityService = velocityService;
	}

	public void setViewWishListDao(ObjectDao<ViewWishList> viewWishListDao) {
		this.viewWishListDao = viewWishListDao;
	}

	public void setVirtualBalanceDao(ObjectDao<VirtualBalance> virtualBalanceDao) {
		this.virtualBalanceDao = virtualBalanceDao;
	}

	public void setWishListDao(ObjectDao<WishList> wishListDao) {
		this.wishListDao = wishListDao;
	}

	@Override
	@Transactional(readOnly = false)
	public AddressBook updateAddressBook(AddressBook addressBook) throws CoreException {
		addressBook = getAddressBookDao().update(addressBook);
		return addressBook;
	}

	@Override
	@Transactional(readOnly = false)
	public BlackList updateBlackList(BlackList blackList) throws CoreException {
		if (blackList.getBlockStatus().equals(BLACK_BOOK_BLOCK_STATUS_NO)) {// 停用-解锁
			blackList.setUnBlockDate(DateUtil.getToday().getTime());
		}
		blackList = getBlackListDao().update(blackList);
		updateBlockStatus(blackList);
		return blackList;
	}

	/**
	 * 更新會員黑名單狀態
	 * 
	 * @param blackList
	 * @return
	 * @throws CoreException
	 */
	Member updateBlockStatus(BlackList blackList) throws CoreException {
		Member member = getDao().get(blackList.getMemberId());
		if (blackList.getBlockStatus().equals(BLACK_BOOK_BLOCK_STATUS_NO)) {// 停用-解锁
			member.setBlackListId(0);
			member.setStatus("00");
			member.setUnBlockDate(blackList.getUnBlockDate());
		} else {
			member.setStatus(blackList.getBlockType());
			member.setBlackListId(blackList.getId());
			member.setUnBlockDate(null);
		}
		member = getDao().update(member);
		return member;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#updateEDMStatus(java.lang.String, java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member updateEDMStatus(String loginId, String edm_status, String sms_status) throws CoreException {
		Member member = getMemberByLoginId(loginId);
		if (null == member) {
			return null;
		}
		member.setEdm(edm_status);
		member.setSms(sms_status);
		member = super.update(member);
		return member;
	}

	@Override
	@Transactional(readOnly = false)
	public Member updateMember(Member entity) throws CoreException {
		Member member = null;
		try {
			member = getDao().update(entity);
			// TODO 更新balance资料待确认
			// 更新balance资料
			reCalculateBalance(member.getMemberId());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return member;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#updateMemberEmail(java.lang.String)
	 */
	@Override
	@Transactional(readOnly = false)
	public Member updateMemberEmail(String memberId) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		List<Member> members = getList(0, -1, crit, null);
		if (members.size() == 1) {
			Member member = members.get(0);
			if (isEmailExist(member.getTempEmail(), member)) {
				member.setActivateToken(null);
				if (StringUtils.isNotBlank(member.getEmail())) {
					member.setTempEmail(null);
				}
				super.update(member);
				return null;
			}

			if (StringUtils.isNotBlank(member.getEmail())) {
				// 寄送修改email成功信函
				Map<String, Object> contentMap = new HashMap<String, Object>();
				Date date = new Date();
				DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				contentMap.put("customerFax", ServerValue.getCustomerFax());
				contentMap.put("customerTel", ServerValue.getCustomerTel());
				contentMap.put("date", dateFormat.format(date));
				contentMap.put("basehref", "http://" + member.getDomainSrc());
				contentMap.put("contextpath", ServerValue.getFrontContextPath());
				contentMap.put("omail", member.getEmail());
				contentMap.put("nmail", member.getTempEmail());
				contentMap.put("loginId", member.getLoginId());
				contentMap.put("domainSrc", member.getDomainSrc());
				Mail mail = velocityService.formatToMail("member.modifyEmailSuccess", contentMap);
				mail.setTo(member.getTempEmail());
				mail.setFrom(mailFrom);
				mailService.save(mail);
			}
			member.setEmail(member.getTempEmail());
			member.setActivateToken(null);
			member.setTempEmail(null);
			super.update(member);
			checkCompleteInfoBonus(member);// 检查是否发送积分
			return member;
		}
		return null;
	}

	@Override
	@Transactional(readOnly = false)
	public Member updateMemberPwd(String loginId, String newPwd) throws CoreException {
		Member member = getMemberByLoginId(loginId);
		if (null != member) {
			// 密码加密
			member.setPwd(passwordEncoder.encodePassword(newPwd, null));
			member = super.update(member);
		}
		return member;
	}

	@Override
	@Transactional(readOnly = false)
	public Balance updateOrder2PayBalance(String memberId) {
		int orderCount = generateOrderService.getOrderTypeCount(memberId, BLACK_BOOK_BLOCK_STATUS_YES);

		Balance memberBalance = getBalance(memberId);
		if (orderCount >= 0) {
			memberBalance.setOrderToPay(new BigDecimal(orderCount));
			memberBalance = saveOrUpdateBalance(memberBalance);
		}
		return memberBalance;
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = false)
	public boolean sendRestockRemindEmail() {
		StringBuilder sb = new StringBuilder("");

		sb.append("Select Evwl.Member_Id, Evwl.Product_Id, nvl(Evwl.Promote_Name,' '),  ");
		sb.append("Epm.Product_Name, Epm.Product_Brief, epm.list_price, Evwl.Shelf_Price, Evwl.id ");
		sb.append("From Ec_View_Wish_List Evwl, ec_product_main epm ");
		sb.append("Where Evwl.Is_Restock_Notify = 'Y' And Evwl.Shelf_Qty > 0 And Evwl.Shelf_Price Is Not Null ");
		sb.append("And Evwl.Product_Id = Epm.Product_Id And Epm.Is_Delete = 'N' ");
		List<String> restockList = getDao().getSQLQueryByList(sb.toString(), null, 0, -1);

		Object[] obj = restockList.toArray();
		for (int iOd = 0; iOd < obj.length; iOd++) {
			Object[] obj2 = (Object[]) obj[iOd];
			Member member = get(obj2[0].toString());
			if (StringUtils.isNotBlank(member.getSendEmail())) {
				Map<String, Object> contentMap = new HashMap<String, Object>();
				contentMap.put("basehref", "http://" + member.getDomainSrc());
				contentMap.put("contextpath", ServerValue.getFrontContextPath());
				contentMap.put("loginId", member.getLoginId());
				contentMap.put("domainSrc", member.getDomainSrc());
				contentMap.put("obj", obj2);
				Mail mail = velocityService.formatToMail("member.RestockRemind", contentMap);
				mail.setTo(member.getSendEmail());
				mail.setFrom(mailFrom);
				mail = mailService.save(mail);
				WishList wl = getWishList(Integer.parseInt(obj2[7].toString()));
				wl.setIsRestockNotify(BLACK_BOOK_BLOCK_STATUS_NO);
				updateWishList(wl);
			}
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = false)
	public boolean sendRestockRemindDeleteEmail() {
		StringBuilder sb = new StringBuilder("");

		sb.append("Select Evwl.Member_Id, Evwl.Product_Id, nvl(Evwl.Promote_Name,' '), ");
		sb.append("Epm.Product_Name, Epm.Product_Brief, Evwl.id, ");
		sb.append("SUBSTR(ecm.category_path,1,INSTR(ecm.category_path,'/',1)-1) ");
		sb.append("From Ec_View_Wish_List Evwl, ec_product_main epm, ec_category_main ecm ");
		sb.append("Where Evwl.Is_Restock_Notify = 'Y' And Evwl.Product_Id = Epm.Product_Id ");
		sb.append("And Epm.Is_Delete = 'Y' and ecm.category_id = epm.main_category_id ");
		List<String> restockList = getDao().getSQLQueryByList(sb.toString(), null, 0, -1);

		Object[] obj = restockList.toArray();
		for (int iOd = 0; iOd < obj.length; iOd++) {
			Object[] obj2 = (Object[]) obj[iOd];
			Member member = get(obj2[0].toString());
			if (StringUtils.isNotBlank(member.getSendEmail())) {
				Map<String, Object> contentMap = new HashMap<String, Object>();
				contentMap.put("basehref", "http://" + member.getDomainSrc());
				contentMap.put("contextpath", ServerValue.getFrontContextPath());
				contentMap.put("loginId", member.getLoginId());
				contentMap.put("domainSrc", member.getDomainSrc());
				contentMap.put("obj", obj2);
				Mail mail = velocityService.formatToMail("member.RestockRemindDelete", contentMap);
				mail.setTo(member.getSendEmail());
				mail.setFrom(mailFrom);
				mail = mailService.save(mail);
				getWishListDao().deleteByPK(Integer.parseInt(obj2[5].toString()));
			}
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = false)
	public boolean sendRestockRemindPMEmail() {
		StringBuilder sb = new StringBuilder("");
		sb.append("select * from ");
		sb.append("( select u.user_name,u.user_email, p.product_id ,p.product_name,p.arrival_date, ");
		sb.append("w.restock_date,count(w.product_id) stock_qty, ");
		sb.append("sa.companyname||'('||sa.supplier_id||')',w.shelf_qty,p.main_category_id ");
		sb.append("from comm_admin_user u,ec_product_main p,ec_view_wish_list w,ec_category_main m, ");
		sb.append("ec_supplier_apply sa ");
		sb.append("where u.user_name = p.pm_id ");
		sb.append("and p.supplier_id = sa.supplier_id ");
		sb.append("and m.category_id = p.main_category_id ");
		sb.append("and w.product_id = p.product_id ");
		sb.append("and w.shelf_qty = 0 ");
		sb.append("and w.is_restock_notify = 'Y' ");
		sb.append("and p.is_delete = 'N' ");
		sb.append("group by ");
		sb.append("u.user_name,u.user_email, p.product_id, p.product_name,p.arrival_date, ");
		sb.append("w.restock_date,sa.companyname||'('||sa.supplier_id||')', ");
		sb.append("w.shelf_qty,p.main_category_id ) aaa ");
		sb.append("left join ");
		sb.append("(select category_id,sys_connect_by_path(category_name||'('||category_id||')', ',') as path ");
		sb.append("from ec_category_main ");
		sb.append("start with parent_id=0 ");
		sb.append("connect by prior category_id=parent_id) bbb ");
		sb.append("on aaa.main_category_id=bbb.category_id ");
		sb.append("where 1 = 1  order by user_name ");
		List<String> restockList = getDao().getSQLQueryByList(sb.toString(), null, 0, -1);
		if (null == restockList || restockList.isEmpty()) {
			return true;
		}
		Object[] obj = restockList.toArray();
		List<Object[]> sendList = new ArrayList<Object[]>();
		for (int iOd = 0; iOd < obj.length; iOd++) {
			Object[] obj2 = (Object[]) obj[iOd];
			if (sendList.size() == 0 || obj2[0].toString().equals(sendList.get(sendList.size() - 1)[0].toString())) {
				sendList.add(obj2);
				continue;
			}
			sendPMMail(sendList);
			sendList = new ArrayList<Object[]>();
			sendList.add(obj2);
		}
		if (sendList.size() > 0) {
			sendPMMail(sendList);
		}
		return true;
	}

	@Transactional(readOnly = false)
	private void sendPMMail(List<Object[]> sendList) {
		Map<String, Object> contentMap = new HashMap<String, Object>();
		contentMap.put("basehref", ServerValue.getMidHostname());
		contentMap.put("contextpath", ServerValue.getMidContextPath());
		contentMap.put("sendList", sendList);
		contentMap.put("name", sendList.get(sendList.size() - 1)[0].toString());
		Mail mail = velocityService.formatToMail("pm.RestockRemind", contentMap);
		mail.setTo(sendList.get(sendList.size() - 1)[1].toString());
		mail.setFrom(mailFrom);
		mail = mailService.save(mail);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.member.service.MemberService#updateWishList(com.yaodian100.ec.member.entity.WishList)
	 */
	@Override
	@Transactional(readOnly = false)
	public WishList updateWishList(WishList wishList) throws CoreException {
		wishList = getWishListDao().update(wishList);
		return wishList;
	}

	@Override
	public MemberGift getMemberGift(Member member) throws CoreException {
		return memberEventService.checkActiveGift(member);
	}

	@Override
	public MemberEvent getMemberEvent(Member member) throws CoreException {
		return memberEventService.getActiveBonus_Coupon(member);
	}

	@Override
	@Transactional(readOnly = false)
	public MemberEvent checkMemberEvent(Member member) throws CoreException {
		return memberEventService.checkActiveBonus_Coupon(member);
	}

	@Override
	public boolean isJoined(String memberId, String surveyId) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		crit.addEq("memo1", surveyId);
		if (getMemberMemoDao().getListSize(crit).intValue() > 0) {
			return true;
		}
		return false;
	}

	@Override
	@Transactional(readOnly = false)
	public boolean saveSurveyData(Member member, MemberMemo memberMemo, MemberProfile memberProfile) throws CoreException {
		try {
			if (null != member) {
				update(member);
			}
			getMemberMemoDao().saveOrUpdate(memberMemo);
			if (null != memberProfile) {
				getMemberProfileDao().saveOrUpdate(memberProfile);
			}
		} catch (Exception e) {
			System.out.println("saveSurveyData error{}: " + e.getMessage());
			return false;
		}
		return true;
	}

	@Override
	public MemberProfile getMemberProfile(String memberId) throws CoreException {
		CommonCriteria crit = new CommonCriteria();
		crit.addEq(FIELD_NAME_MEMBER_ID, memberId);
		List<MemberProfile> memberProfiles = getMemberProfileDao().getList(crit, null);
		if (memberProfiles.size() == 1) {
			return memberProfiles.get(0);
		} else {
			return null;
		}
	}

	public ObjectDao<MemberMemo> getMemberMemoDao() {
		return memberMemoDao;
	}

	public void setMemberMemoDao(ObjectDao<MemberMemo> memberMemoDao) {
		this.memberMemoDao = memberMemoDao;
	}

	public ObjectDao<MemberProfile> getMemberProfileDao() {
		return memberProfileDao;
	}

	public void setMemberProfileDao(ObjectDao<MemberProfile> memberProfileDao) {
		this.memberProfileDao = memberProfileDao;
	}

	@Override
	@Transactional(readOnly = false)
	public String receiverBlackBookArray(String[] blockType, String[] blockContent) throws CoreException {
		String isSuccess = "true";
		String errBlockType = "";
		String errBlockContent = "";
		CommonCriteria crit = new CommonCriteria();
		try {
			for (int i = 0; i < blockType.length; i++) {
				errBlockType = blockType[i];
				errBlockContent = blockContent[i];
				crit.addEq("blockType", blockType[i]);
				crit.addEq("blockContent", blockContent[i]);
				crit.addEq("blockStatus", BLACK_BOOK_BLOCK_STATUS_YES);
				crit.addLe("blockStartdate", new Date());
				crit.addGe("blockEnddate", new Date());
				List<ReceiverBlackBook> receiverBlackBooks = getReceiverBlackBookDao().getList(crit, null);
				ReceiverBlackBook obj;
				if (receiverBlackBooks.size() > 0) {
					obj = receiverBlackBooks.get(0);
				} else {
					obj = new ReceiverBlackBook();
				}
				obj.setBlockType(blockType[i]);
				obj.setBlockContent(blockContent[i]);
				obj.setBlockStartdate(new Date());
				obj.setBlockEnddate(DateUtils.addDays(new Date(), 2));
				obj.setBlockStatus(BLACK_BOOK_BLOCK_STATUS_YES);
				getReceiverBlackBookDao().saveOrUpdate(obj);
			}
		} catch (Exception e) {
			isSuccess = "[ERROR_receiverBlackBookArray]errBlockType:" + errBlockType + " errBlockContent:" + errBlockContent;
		}
		return isSuccess;
	}

	@Override
	public String greykBookArray(String[] memberId) throws CoreException {
		String isSuccess = "true";
		String errmemberId = "";
		try {
			for (int i = 0; i < memberId.length; i++) {
				errmemberId = memberId[i];
				jdbcTemplate.execute("call sp_grey_book('" + memberId[i].trim() + "')");
			}
		} catch (Exception e) {
			isSuccess = "[ERROR_greykBookArray]errmemberId:" + errmemberId;
		}
		return isSuccess;
	}

	@Override
	@Transactional(readOnly = false)
	public BlackBook addBlackBookByMemberId(BlackBook blackBook) {
		String memberId = blackBook.getMemberId();
		List<BlackBook> existingBlackBookList = getBlackBookListByMemberId(memberId);
		if (existingBlackBookList.size() > 0) {
			BlackBook latestBlackBook = existingBlackBookList.get(0);
			if (latestBlackBook.getBlockStatus().equals(BLACK_BOOK_BLOCK_STATUS_YES)) {
				return null;
			}
		}

		BlackBook result = new BlackBook();
		BeanUtils.copyProperties(blackBook, result);
		result.setBlockStatus(BLACK_BOOK_BLOCK_STATUS_YES);
		getBlackBookDao().save(result);

		return result;
	}

	@Override
	@Transactional(readOnly = false)
	public BlackBook unblockBlackBook(BlackBook blackBook) {
		BlackBook targetBlackBook = this.blackBookDao.get(blackBook.getId());

		targetBlackBook.setUnblockReason(blackBook.getUnblockReason());
		targetBlackBook.setUnblockReasonDesc(blackBook.getUnblockReasonDesc());
		targetBlackBook.setBlockStatus(BLACK_BOOK_BLOCK_STATUS_NO);

		this.blackBookDao.save(targetBlackBook);

		return targetBlackBook;
	}

	@Override
	@Transactional(readOnly = false)
	public BlackBook unblockBlackBookByBlackBookId(Integer blackBookId) {
		BlackBook blackBook = this.blackBookDao.get(blackBookId);
		blackBook.setBlockStatus(BLACK_BOOK_BLOCK_STATUS_NO);
		this.blackBookDao.save(blackBook);

		return blackBook;
	}

	@Override
	public boolean isBlackBookAddableByMemberId(String memberId) {
		Member member = this.getDao().get(memberId);
		if (member == null) {
			return false;
		}
		BlackBook latestBlackBook = latestBlackBookByMemberId(memberId);
		if (latestBlackBook == null) {
			return true;
		}

		if (BLACK_BOOK_BLOCK_STATUS_YES.equals(latestBlackBook.getBlockStatus())) {
			return false;
		}

		return true;
	}

	public BlackBook latestBlackBookByMemberId(String memberId) {
		List<BlackBook> existingBlackBookList = getBlackBookListByMemberId(memberId);
		if (existingBlackBookList.size() > 0) {
			BlackBook latestBlackBook = existingBlackBookList.get(0);
			return latestBlackBook;
		}

		return null;
	}

	@Override
	public List<BlackBook> getBlackBookListByMemberId(String memberId) {
		CommonCriteria criteria = new CommonCriteria();
		criteria.addEq(FIELD_NAME_MEMBER_ID, memberId);
		List<BlackBook> existingBlackBookList = this.blackBookDao.getList(criteria, new String[] { "createDate desc" });
		return existingBlackBookList;
	}

	@Override
	@Transactional(readOnly = false)
	public BlackBookImportResult importBlackBookList(File file) throws FileNotFoundException, IOException {
		BlackBookImportResult result = null;
		if (file == null) {
			return null;
		}
		LineNumberReader reader = null;
		reader = new LineNumberReader(new FileReader(file));
		int totalCount = 0;
		int successCount = 0;
		int failCount = 0;
		while (reader.ready()) {
			String str = reader.readLine();
			if (StringUtils.isNotEmpty(str)) {
				totalCount++;
				String oneLine = StringUtils.trimToEmpty(str);

				BlackBook blackBook = new BlackBook();
				String[] columns = StringUtils.split(oneLine, ',');

				String memberId = null;
				String blockReason = null;
				String blockReasonDesc = null;
				if (columns.length >= 1) {
					memberId = columns[0];
				}
				if (columns.length >= 2) {
					blockReason = columns[1];
				}
				if (columns.length >= 3) {
					blockReasonDesc = columns[2];
				}
				blackBook.setMemberId(memberId);
				blackBook.setBlockReason(blockReason);
				blackBook.setBlockReasonDesc(blockReasonDesc);

				boolean isBlackBookAddable = this.isBlackBookAddableByMemberId(memberId);
				if (isBlackBookAddable) {
					this.addBlackBookByMemberId(blackBook);
					successCount++;
				} else {
					failCount++;
				}
			}
		}

		result = new BlackBookImportResult();
		result.setTotalCount(totalCount);
		result.setSuccessCount(successCount);
		result.setFailCount(failCount);
		return result;
	}

	public ObjectDao<ReceiverBlackBook> getReceiverBlackBookDao() {
		return receiverBlackBookDao;
	}

	public void setReceiverBlackBookDao(ObjectDao<ReceiverBlackBook> receiverBlackBookDao) {
		this.receiverBlackBookDao = receiverBlackBookDao;
	}

	public ObjectDao<GreyBook> getGreyBookDao() {
		return greyBookDao;
	}

	public void setGreyBookDao(ObjectDao<GreyBook> greyBookDao) {
		this.greyBookDao = greyBookDao;
	}

	@Override
	@Transactional(readOnly = false)
	public String greyToBlackBook() throws CoreException {// 灰名单升级黑名单
		String isSuccess = "true";
		String errmemberId = "";
		String paramBlock_status = BLACK_BOOK_BLOCK_STATUS_YES;
		CommonCriteria crit = new CommonCriteria();
		try {
			// 找出灰名单沒有在黑名单里的就新增
			String sqlb = "select member_id from ec_member_grey_book where grey_count >=3 and block_status=? and member_id not in(select member_id from ec_member_black_book where block_status=?)";
			List<Map<String, Object>> blackList = jdbcTemplate.queryForList(sqlb, paramBlock_status, paramBlock_status);
			for (Iterator<Map<String, Object>> blacks = blackList.iterator(); blacks.hasNext();) {
				Map<String, Object> black = blacks.next();
				String memberId = (String) black.get("member_id");
				errmemberId = memberId;
				BlackBook blackBook = new BlackBook();
				blackBook.setBlockStatus(BLACK_BOOK_BLOCK_STATUS_YES);
				blackBook.setMemberId(memberId);
				blackBook.setBlockReason(BLOCK_REASON_FOR_GREY_TO_BLACK_BOOK);
				getBlackBookDao().save(blackBook);
			}
			// 找出灰名单3次的就更新狀態
			String sqlg = "update ec_member_grey_book set block_status='N' where member_id in(select member_id from ec_member_grey_book where grey_count >=3 and block_status='Y')";
			jdbcTemplate.execute(sqlg);
		} catch (Exception e) {
			logger.error(e.toString());
			isSuccess = "[ERROR_greyToBlackBook]errmemberId:" + errmemberId;
		}
		return isSuccess;
	}

	public ObjectDao<BlackBook> getBlackBookDao() {
		return blackBookDao;
	}

	public void setBlackBookDao(ObjectDao<BlackBook> blackBookDao) {
		this.blackBookDao = blackBookDao;
	}

	@Override
	public String badMemberCheck(String aMemberId) throws CoreException {
		String isSuccess = "";
		try {
			StringBuffer sbo = new StringBuffer();
			sbo.append("select member_id,null as block_type,null as block_content from ec_member_black_book b ");
			sbo.append("where block_status='Y' and member_id = ? ");
			List<Map<String, Object>> blackList = jdbcTemplate.queryForList(sbo.toString(), aMemberId);
			if (blackList.size() > 0) {
				isSuccess = "帐号异常";
			} else {
				isSuccess = "true";
			}
		} catch (Exception e) {
			logger.error(e.toString());
			isSuccess = "[ERROR_badMemberCheck]err:" + aMemberId;
		}
		return isSuccess;
	}

	@Override
	public String badOrderCheck(String aMemberId, String receiverAdd, String receiverMobile, String receiverPhone)
			throws CoreException {
		String isSuccess = "";
		try {
			StringBuffer sbo = new StringBuffer();
			sbo.append("select * from ( ");
			sbo
					.append("select '' as member_id,'ADD' as block_type ,count(*) as total, 'adderr' as block_content  from ec_order_main b ");
			sbo.append("where b.order_dt < sysdate and b.order_dt > (SYSDATE - 4/24) and ");
			sbo.append("b.receiver_addr =? and not exists ( select a.block_type from ec_member_receiver_white_book a ");
			sbo.append("where a.block_content = b.receiver_addr and a.block_type = 'ADD') and not exists ( ");
			sbo.append("select e.order_id from ec_order_main e ");
			sbo.append("where e.order_dt > (SYSDATE -1 ) and e.receiver_addr = b.receiver_addr and e.payment_st = '10') ");
			sbo.append("union ");
			sbo
					.append("select '' as member_id,'MOB' as block_type,count(*) as total, 'moberr' as block_content  from ec_order_main b ");
			sbo.append("where b.order_dt < sysdate and b.order_dt > (SYSDATE - 4/24) and ");
			sbo.append("b.receiver_mobile = ? and not exists ( select a.block_type from ec_member_receiver_white_book a ");
			sbo.append("where a.block_content = b.receiver_mobile and a.block_type = 'MOB') and not exists ( ");
			sbo.append("select e.order_id from ec_order_main e ");
			sbo
					.append("where e.order_dt > (SYSDATE -1 ) and e.receiver_mobile = b.receiver_mobile and e.payment_st = '10') ");
			sbo.append("union ");
			sbo
					.append("select '' as member_id,'TEL' as block_type ,count(*) as total, 'telerr' as block_content  from ec_order_main b ");
			sbo.append("where b.order_dt < sysdate and b.order_dt > (SYSDATE - 4/24) and ");
			sbo.append("b.receiver_phone = ? and not exists ( select a.block_type from ec_member_receiver_white_book a ");
			sbo.append("where a.block_content = b.receiver_phone and a.block_type = 'TEL') and not exists ( ");
			sbo.append("select e.order_id from ec_order_main e ");
			sbo.append("where e.order_dt > (SYSDATE -1 ) and e.receiver_phone = b.receiver_phone and e.payment_st = '10') ");
			sbo.append(") where total > 4 ");
			sbo.append("union ");
			sbo.append("select '' as member_id,block_type,1 as total ,block_content from ec_member_receiver_black_book r ");
			sbo.append("where block_status='Y' and sysdate between block_startdate and block_enddate ");
			sbo.append("and block_content in(?,?,?)");
			List<Map<String, Object>> blackList = jdbcTemplate.queryForList(sbo.toString(), receiverAdd.trim(),
					receiverMobile.trim(), receiverPhone.trim(), receiverAdd.trim(), receiverMobile.trim(), receiverPhone.trim());
			if (blackList.size() > 0) {
				for (Iterator<Map<String, Object>> blacks = blackList.iterator(); blacks.hasNext();) {
					Map<String, Object> black = blacks.next();
					String blockType = (String) black.get("block_type");
					String blockContent = (String) black.get("block_content");
					if (null != blockContent) {
						if ("ADD".equals(blockType)) {
							isSuccess = isSuccess + "收货地址异常";
							break;
						}
						if ("MOB".equals(blockType)) {
							isSuccess = isSuccess + "收货行动电话异常";
							break;
						}
						if ("TEL".equals(blockType)) {
							isSuccess = isSuccess + "收货电话异常";
							break;
						}
					}
				}
			} else {
				isSuccess = "true";
			}
		} catch (Exception e) {
			logger.error(e.toString());
			isSuccess = "[ERROR_badOrderCheck]err:" + aMemberId + "," + receiverAdd + "," + receiverMobile + ","
					+ receiverPhone;
		}
		return isSuccess;
	}

	@Override
	@Transactional(readOnly = false)
	public String clearRegMobileInfo(String memberId, String type) {
		Member member = get(memberId);
		if (null == member) {
			return "找不到會員";
		}
		boolean changed = false;
		MemberMemo mm = new MemberMemo();
		mm.setMemberId(member.getMemberId());
		mm.setMemo1(type);
		if (("1".equals(type) || "3".equals(type)) && null != member.getLastMobileModifyDate()) {
			mm.setMemo2(new SimpleDateFormat("yyyy/MM/dd HH-mm-ss").format(member.getLastMobileModifyDate()));
			member.setLastMobileModifyDate(null);
			changed = true;
		}
		if (("2".equals(type) || "3".equals(type)) && member.getMobileModifyCount() != 0) {
			mm.setMemo3(Integer.toString(member.getMobileModifyCount()));
			member.setMobileModifyCount(0);
			changed = true;
		}
		if (changed) {
			getMemberMemoDao().saveOrUpdate(mm);
			save(member);
		}
		return "清除成功";
	}

	/**
	 * 退货取消积分
	 */
	@Override
	public BigDecimal cancelOrderBonus(BigDecimal cancelAmount, String orderId, String memberId) throws Exception {
		CommonCriteria criteria = new CommonCriteria();
		criteria.addEq("orderId", orderId);
		criteria.addEq("memberId", memberId);
		criteria.addEq("trxType", "ORDER_BONUS");
		List<Bonus> bonusList = getBonusDao().getList(criteria, null);
		if (null == bonusList || bonusList.isEmpty()) {
			return null;
		}
		Bonus bonus = bonusList.get(0);
		BigDecimal availableBonus = bonus.getTrxAmount().subtract(bonus.getUseBonus()).add(bonus.getRefoundBonus());
		if (availableBonus.compareTo(BigDecimal.ZERO) != 1) {
			return null;
		}
		if (availableBonus.compareTo(cancelAmount) == -1) {// 剩馀积分小于追回积分, 只追回剩馀的部份
			cancelAmount = availableBonus;
		}
		bonus.setTrxAmount(bonus.getTrxAmount().subtract(cancelAmount));
		bonus.setDescription(bonus.getDescription() + "（退货取消" + cancelAmount.toString() + "积分）");
		saveOrUpdateBonus(bonus);
		return cancelAmount;
	}

	/**
	 * 检查资料是否齐全并发送积分
	 * 
	 * @param member
	 * @return
	 */
	private boolean checkCompleteInfoBonus(Member member) {
		if ("2".equals(member.getCrmUpdate())) {
			if (StringUtils.isNotBlank(member.getEmail()) && StringUtils.isNotBlank(member.getMobile())
					&& StringUtils.isNotBlank(member.getSex()) && (null != member.getBirthday())) {
				try {
					Option option = menuService.get("SystemValue").getOptions().get("complete_info_bonus");
					giveBonus(member.getMemberId(), new BigDecimal(option.getMemo1()), option.getName(), null, null, null);
					member.setCrmUpdate("3"); // 资料填写完成
					member.setGetBonus(Integer.parseInt(option.getMemo1()));
					save(member);
					return true;
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		member.setGetBonus(0);
		return false;
	}

	@Override
	@Transactional(readOnly = false)
	public Member updateSexAndBirthday(Member member, String sex, String date) throws ParseException {
		if (StringUtils.isBlank(member.getCrmUpdate()) || "1".equals(member.getCrmUpdate())) {
			member.setSex(sex);
			DateFormat df = new SimpleDateFormat("yyyyMMdd");
			member.setBirthday(df.parse(date));
			member.setCrmUpdate("2");
			save(member);
			checkCompleteInfoBonus(member);// 检查是否发送积分
		}
		return member;
	}

	@Override
	@Transactional(readOnly = false)
	public String showCompleteInfoDialog(Member member) {
		if (StringUtils.isBlank(member.getCrmUpdate())) {
			member.setCrmUpdate("1");
			save(member);
			return "Y";
		}
		return "N";
	}

	/**
	 * 发放积分
	 * 
	 * @throws Exception
	 */
	@Override
	@Transactional(readOnly = false)
	public void giveBonus(String memberId, BigDecimal amount, String description, String trxType, Date startDate,
			Date endDate) throws Exception {
		Bonus bonus = new Bonus();
		bonus.setMemberId(memberId);
		bonus.setTrxAmount(amount);
		bonus.setTrxType(StringUtils.isBlank(trxType) ? "EVENT_POINT" : trxType);
		bonus.setTrxDate(new Date());
		bonus.setDescription(description);
		DateFormat df = new SimpleDateFormat("yyyyMMdd");
		DateFormat df2 = new SimpleDateFormat("yyyyMMddHHmmss");
		bonus.setStartDate(null == startDate ? df.parse(df.format(new Date())) : df.parse(df.format(startDate)));// default立即生效
		if (null == endDate) {
			Date expireDate = df.parse(new SimpleDateFormat("yyyyMM").format(DateUtils.addMonths(bonus.getStartDate(), 13))
					+ "01");// default效期固定到隔年月底
			bonus.setExpireDate(new Date(expireDate.getTime() - 1));
		} else {
			bonus.setExpireDate(df2.parse(df.format(endDate) + "235959"));
		}
		bonus = saveOrUpdateBonus(bonus);
	}
}